package com.pmdesigns.sqlmapper;


import java.util.*;


/**
 * This class is basically just a data structure for holding
 * information extracted from an annotated database column 
 * definition.
 * <p>
 * It is intened that its public fields be accessed directly from java-code-tags
 * and java-expression-tags in template files.
 *
 * @author mike dooley
 */
public class Field implements Comparable<Field> {
	/**
	 * The database column this field is based on
	 */
	public String columnName;

	/**
	 * The database column type this field is based on, The parser actually just puts
	 * everything it finds after the column name and the @field comment in the columnType
	 */
	public String columnType;

	/**
	 * The name of the model field,  This is either set automatically based on the columnName or
	 * manually by an @field property.
	 */
	public String fieldName;

	/**
	 * The type of the model field, This is either set automatically based on the columnType
	 * and the configuration file column-to-field type mappings or manually by an @field property.
	 */
	public String fieldType;

	/**
	 * This will be true if there was an <em>pk</em> attribute in the @field annotation
	 */
	public boolean primaryKey;

	/**
	 * This will be true if there was an <em>auto_inc</em> attribute in the @field annotation
	 */
	public boolean autoIncrement;

	/**
	 * This will be true if there was an <em>not_mapped</em> attribute in the @field annotation
	 */
	public boolean notMapped;
	
	String has1;
	String has1to1;
	String belongs2;
	String h1b2;
	String image;
	int beginLine;

	
	Field(Token t, String image) throws ParseException {
		beginLine = t.beginLine;
		this.image = image;

		String s = image.trim();
		int idx = s.indexOf(' ');
		if (idx == -1) idx = s.indexOf('\t');
		if (idx == -1) throw new ParseException("Invalid field name definition '"+image+"' on line "+beginLine);
		columnName = s.substring(0,idx);
		
		s = s.substring(idx+1);
		idx = s.indexOf(' ');  // look for space terminator
		if (idx == -1) idx = s.indexOf('\t'); // look for tab terminator
 		if (idx == -1) idx = s.length(); // just use the whole thing
		columnType = s.substring(0,idx);
		if (columnType.endsWith(",")) {
			columnType = columnType.substring(0,columnType.length()-1);
		}
	}
	
	public int compareTo(Field f) {
		if (f == null) return 1;
		return columnName.compareTo(f.columnName);
	}
	
	void addKeyValue(Token t) throws ParseException {
		String s = t.image.trim();
		int idx = s.indexOf('=');
		if (idx == -1) throw new ParseException("Invalid field key/value '"+s+"' on line "+t.beginLine);
		String key = s.substring(0,idx);
		String val = s.substring(idx+1);
		if ("name".equals(key)) {
			fieldName = val;
		} else if ("type".equals(key)) {
			fieldType = val;
		} else if ("has1".equals(key)) {
			has1 = val;
		} else if ("has1to1".equals(key)) {
			has1to1 = val;
		} else if ("belongs2".equals(key)) {
			belongs2 = val;
		} else if ("h1b2".equals(key)) {
			h1b2 = val;
		} else {
			throw new ParseException("Unknown field key/value '"+s+"' on line "+t.beginLine);
		}
	}

	void addAttr(Token t) throws ParseException {
		String s = t.image.trim();
		if ("pk".equals(s)) {
			primaryKey = true;
		} else if ("auto_inc".equals(s)) {
			autoIncrement = true;
		} else if ("not_mapped".equals(s)) {
			notMapped = true;
		} else {
			throw new ParseException("Unknown field attr '"+s+"' on line "+t.beginLine);
		}
	}

	public boolean isPrimitive() {
		return "int,long,float,double,short,byte,char,boolean".indexOf(fieldType) != -1;
	}
	
	public boolean isArray() {
		return fieldType != null && fieldType.indexOf("[]") != -1;
	}
	
	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append("column: ").append(columnName).append(", col type: ").append(columnType);
		sb.append(", field: ").append(fieldName).append(", field type: ").append(fieldType);
		sb.append(", primary key: ").append(primaryKey).append(", autoIncr: ").append(autoIncrement);
		sb.append(", line: ").append(beginLine);
		if (has1 != null) sb.append(", has1: ").append(has1);
		if (has1to1 != null) sb.append(", 1to1: ").append(has1to1);
		if (belongs2 != null) sb.append(", belongs2: ").append(belongs2);
		if (h1b2 != null) sb.append(", h1b2: ").append(h1b2);
		return sb.toString();
	}
}
